001 /* 002 * Copyright 2003-2005 The Apache Software Foundation 003 * Copyright 2005 Stephen McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package net.dpml.cli.commandline; 018 019 import java.io.IOException; 020 021 import java.util.LinkedList; 022 import java.util.List; 023 import java.util.ListIterator; 024 025 import net.dpml.cli.CommandLine; 026 import net.dpml.cli.Group; 027 import net.dpml.cli.Option; 028 import net.dpml.cli.OptionException; 029 import net.dpml.cli.WriteableCommandLine; 030 import net.dpml.cli.resource.ResourceConstants; 031 import net.dpml.cli.util.HelpFormatter; 032 033 /** 034 * A class that implements the <code>Parser</code> interface can parse a 035 * String array according to the {@link Group}specified and return a 036 * {@link CommandLine}. 037 * 038 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 039 * @version 1.0.0 040 */ 041 public class Parser 042 { 043 private HelpFormatter m_helpFormatter = new HelpFormatter(); 044 private Option m_helpOption = null; 045 private String m_helpTrigger = null; 046 private Group m_group = null; 047 048 /** 049 * Parse the arguments according to the specified options and properties. 050 * 051 * @param arguments the command line arguments 052 * @return the list of atomic option and value tokens 053 * @throws OptionException if there are any problems encountered while parsing the 054 * command line tokens. 055 */ 056 public CommandLine parse( final String[] arguments ) throws OptionException 057 { 058 // build a mutable list for the arguments 059 final List argumentList = new LinkedList(); 060 061 // copy the arguments into the new list 062 for( int i = 0; i < arguments.length; i++ ) 063 { 064 final String argument = arguments[i]; 065 066 // ensure non intern'd strings are used 067 // so that == comparisons work as expected 068 argumentList.add( new String( argument ) ); 069 } 070 071 // wet up a command line for this group 072 final WriteableCommandLine commandLine = 073 new WriteableCommandLineImpl( m_group, argumentList ); 074 075 // pick up any defaults from the model 076 m_group.defaults( commandLine ); 077 078 // process the options as far as possible 079 final ListIterator iterator = argumentList.listIterator(); 080 Object previous = null; 081 082 while( m_group.canProcess( commandLine, iterator ) ) 083 { 084 // peek at the next item and backtrack 085 final Object next = iterator.next(); 086 iterator.previous(); 087 // if we have just tried to process this instance 088 if( next == previous ) 089 { 090 // abort 091 break; 092 } 093 // remember previous 094 previous = next; 095 m_group.process( commandLine, iterator ); 096 } 097 098 // if there are more arguments we have a problem 099 if( iterator.hasNext() ) 100 { 101 final String arg = (String) iterator.next(); 102 throw new OptionException( 103 m_group, 104 ResourceConstants.UNEXPECTED_TOKEN, 105 arg ); 106 } 107 108 // no need to validate if the help option is present 109 if( !commandLine.hasOption( m_helpOption ) && !commandLine.hasOption( m_helpTrigger ) ) 110 { 111 m_group.validate( commandLine ); 112 } 113 return commandLine; 114 } 115 116 /** 117 * Parse the arguments according to the specified options and properties and 118 * displays the usage screen if the CommandLine is not valid or the help 119 * option was specified. 120 * 121 * @param arguments the command line arguments 122 * @return a valid CommandLine or null if the parse was unsuccessful 123 * @throws IOException if an error occurs while formatting help 124 */ 125 public CommandLine parseAndHelp( final String[] arguments ) throws IOException 126 { 127 m_helpFormatter.setGroup( m_group ); 128 129 try 130 { 131 // attempt to parse the command line 132 final CommandLine commandLine = parse( arguments ); 133 if( !commandLine.hasOption( m_helpOption ) && !commandLine.hasOption( m_helpTrigger ) ) 134 { 135 return commandLine; 136 } 137 } 138 catch( final OptionException oe ) 139 { 140 // display help regarding the exception 141 m_helpFormatter.setException( oe ); 142 } 143 144 // print help 145 m_helpFormatter.print(); 146 return null; 147 } 148 149 /** 150 * Sets the Group of options to parse against 151 * @param group the group of options to parse against 152 */ 153 public void setGroup( final Group group ) 154 { 155 m_group = group; 156 } 157 158 /** 159 * Sets the HelpFormatter to use with the simplified parsing. 160 * @see #parseAndHelp(String[]) 161 * @param helpFormatter the HelpFormatter to use with the simplified parsing 162 */ 163 public void setHelpFormatter( final HelpFormatter helpFormatter ) 164 { 165 m_helpFormatter = helpFormatter; 166 } 167 168 /** 169 * Sets the help option to use with the simplified parsing. For example 170 * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used. 171 * @see #parseAndHelp(String[]) 172 * @param helpOption the help Option 173 */ 174 public void setHelpOption( final Option helpOption ) 175 { 176 m_helpOption = helpOption; 177 } 178 179 /** 180 * Sets the help option to use with the simplified parsing. For example 181 * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used. 182 * @see #parseAndHelp(String[]) 183 * @param helpTrigger the trigger of the help Option 184 */ 185 public void setHelpTrigger( final String helpTrigger ) 186 { 187 m_helpTrigger = helpTrigger; 188 } 189 }